import { Prop } from 'vue-property-decorator'
import { AxiosResponse } from 'axios'
import { ComponentModel } from '@TG/interface'
import { ITgFormBasicDialog } from '@TG/interface/types/component'
import { emptyResponse, validResponse } from '@TG/kit/request'
import { isEmpty, isNotEmpty } from '@TG/kit/validate'
import TgComponent from '../TgComponent'

/*
prop 列表
  maxHeight: number                                                                   表单最大高度 [默认为 -1，既未指定，各子类按实现需要处理默认值]
  holdHeight: boolean                                                                 保持表单高度 [默认为 true]
  table: {
    tableProps?: Map<string, any>                                                  [参考 ComponentModel.props]
    tableEvents?: Map<string, Function | Function[]>                               [参考 ComponentModel.events]
    handleTableData?: (querier: any, data: any[]) => any[]                            动态处理表格 data
    handleTableItems?: (querier: any) => ComponentModel[]                             动态处理表格 items
    load?: (params: any, page: number, limit: number) => Promise<AxiosResponse<any>>  远程加载表格 data
  }
  controlBar!: {
    leftItems?: ComponentModel[]                                                      [参考 TgControlBar.@Prop.leftItems]
    rightItems?: ComponentModel[]                                                     [参考 TgControlBar.@Prop.rightItems]
    showSearcher?: boolean                                                            是否显示搜索器按钮 [默认为 true]
  }
  searcher!: {
    linkage?: boolean                                                                 [参考 ElFormPackage.@Prop.linkage]
    defaultModel?: any                                                                表单初始化默认 model
    handleFormModel?: (operate: string, model: any) => any                            动态处理表单 model
    handleFormItems?: (operate: string, model: any) => ComponentModel[]               动态处理表单 items
  }
  paginationConfig!: {
    showPagination?: boolean                                                          是否显示分页组件 [默认为 true]
    totalField?: string                                                               分页对象数据总量字段
    itemsField?: string                                                               分页对象数据项字段
    pageLimit?: number                                                                每页条数
  }
controlBar.[leftItems | rightItems].[i].meta 扩展
  selectedRowVisible: boolean                                                         是否选中数据后激活
ref 列表
  ref-table [默认]
  ref-searcher
*/
export default abstract class extends TgComponent {
  @Prop({ type: Number, default: -1 }) protected maxHeight!: number
  @Prop({ type: Boolean, default: true }) protected holdHeight!: boolean
  @Prop({ type: Object, required: true }) protected table!: {
    tableProps?: Map<string, any>
    tableEvents?: Map<string, Function | Function[]>
    handleTableData?: (querier: any, data: any[]) => any[]
    handleTableItems?: (querier: any) => ComponentModel[]
    load?: (params: any, page: number, limit: number) => Promise<AxiosResponse<any>>
  }
  @Prop({ type: Object }) protected controlBar!: {
    leftItems?: ComponentModel[]
    rightItems?: ComponentModel[]
    showSearcher?: boolean
  }
  @Prop({ type: Object, required: true }) protected searcher!: {
    linkage?: boolean
    defaultModel?: any
    handleFormModel?: (operate: string, model: any) => any
    handleFormItems?: (operate: string, model: any) => ComponentModel[]
  }
  @Prop({ type: Object }) protected paginationConfig!: {
    showPagination?: boolean
    totalField?: string
    itemsField?: string
    pageLimit?: number
  }

  protected total: number = 0
  protected page: number = 1
  protected limit: number = this.pageLimit
  protected frozenParams: any = {}
  protected model: any = {}
  protected data: any[] = []
  protected tableItems: ComponentModel[] = []
  protected tableLoading: boolean = false
  protected selectedRows: any[] = []
  protected searcherInitable = true
  protected searcherTitle: string = '搜索器'
  protected searcherHoldHeight: boolean = false

  get tableCM() {
    let maxHeight: number = this.adjustHeight(this.maxHeight)
    if (isNotEmpty(this.hasControlBar)) {
      maxHeight -= 58 // searcher 58
      maxHeight -= 1 // searchermargin 1
    }
    if (this.showPagination) {
      maxHeight -= 1 // paginationmargin 1
      maxHeight -= 2 // paginationborder 2
      maxHeight -= 32 // paginationpadding 32
      maxHeight -= 36 // pagination 36
    }
    const props: Map<string, any> = new Map<string, any>([
      ['data', this.data]
    ])
    if (this.holdHeight) {
      props.set('height', maxHeight)
    } else {
      props.set('max-height', maxHeight)
    }
    Object.assign(props, this.table.tableProps)
    const events: Map<string, Function | Function[]> = new Map<string, Function | Function[]>([
      ['selection-change', (selection: any[]) => this.selectionChange(selection)]
    ])
    Object.assign(events, this.table.tableEvents)
    return {
      props,
      events,
      items: this.tableItems
    }
  }

  get handleTableData() {
    const handleTableData = this.table.handleTableData
    if (isNotEmpty(handleTableData)) {
      return handleTableData as (querier: any, data: any[]) => any[]
    } else {
      return (querier: any, data: any[]) => data
    }
  }

  get handleTableItems() {
    const handleTableItems = this.table.handleTableItems
    if (isNotEmpty(handleTableItems)) {
      return handleTableItems as (querier: any) => ComponentModel[]
    } else {
      return (querier: any) => []
    }
  }

  get load() {
    const load = this.table.load
    if (isNotEmpty(load)) {
      return load as (params: any, page: number, limit: number) => Promise<AxiosResponse<any>>
    } else {
      return (params: any, page: number, limit: number) => Promise.resolve(emptyResponse({}))
    }
  }

  get hasControlBar() {
    return this.controlBarLeftItems.length > 0 || this.controlBarRightItems.length > 0
  }

  get controlBarLeftItems() {
    const leftItems = this.controlBar?.leftItems || []
    const items: ComponentModel[] = []
    leftItems.forEach(item => {
      const selectedRowVisible = item.meta?.selectedRowVisible || false
      if (!selectedRowVisible || isNotEmpty(this.selectedRows)) {
        items.push(item)
      }
    })
    return items
  }

  get controlBarRightItems() {
    const items: ComponentModel[] = []
    const rightItems = this.controlBar?.rightItems || []
    const showSearcher = this.controlBar?.showSearcher === undefined ? true : this.controlBar.showSearcher
    rightItems.forEach(item => {
      const selectedRowVisible = item.meta?.selectedRowVisible || false
      if (!selectedRowVisible || isNotEmpty(this.selectedRows)) {
        items.push(item)
      }
    })
    if (showSearcher) {
      /*
      检查是否有搜索条件
      检查到搜索条件后对按钮进行样式处理，提醒用户
      */
      let tip = ''
      let type = 'primary'
      if (isNotEmpty(this.model)) {
        tip = '点击查看已使用的搜索条件'
        type = 'success'
      }
      items.push({
        tag: 'el-button-package',
        text: '搜索器',
        props: new Map<string, any>([
          ['type', type],
          ['icon', 'el-icon-antd-search']
        ]),
        events: new Map<string, Function | Function[]>([
          ['click', () => this.showSearcher()]
        ]),
        meta: { tip }
      })
    }
    return items
  }

  get searcherLinkage() {
    return this.searcher.linkage || false
  }

  get searcherControlBar() {
    const rightItems: ComponentModel[] = []
    rightItems.push({
      tag: 'el-button-package',
      text: '查  询',
      props: new Map<string, any>([
        ['type', 'primary'],
        ['icon', 'el-icon-antd-search']
      ]),
      events: new Map<string, Function | Function[]>([
        ['click', () => this.doSearch()]
      ])
    })
    return { rightItems, showSave: false }
  }

  get showPagination() {
    return this.paginationConfig?.showPagination === undefined ? true : this.paginationConfig.showPagination && this.total > 0
  }

  get totalField() {
    return this.paginationConfig?.totalField || 'total'
  }

  get itemsField() {
    return this.paginationConfig?.itemsField || 'items'
  }

  get pageLimit() {
    return this.paginationConfig?.pageLimit || 20
  }

  protected abstract adjustHeight(height: number): number

  public initTable(loadData: boolean = true, frozenParams?: any) {
    if (isNotEmpty(frozenParams) && JSON.stringify(frozenParams) !== JSON.stringify(this.frozenParams)) {
      this.frozenParams = frozenParams
    }
    if (loadData) {
      this.doSearch()
    } else {
      const querier = this.getQuerier()
      this.tableItems = this.handleTableItems(querier)
    }
  }

  public getQuerier() {
    return Object.assign({}, this.getSearcherModel(), this.frozenParams)
  }

  protected loadData() {
    const querier = this.getQuerier()
    this.tableLoading = true
    this.load(querier, this.page, this.limit).then(response => {
      if (validResponse(response)) {
        const data = response.data
        if (isNotEmpty(data)) {
          this.total = data[this.totalField] || 0
          this.data = this.handleTableData(querier, data[this.itemsField] || [])
          this.tableItems = this.handleTableItems(querier)
        }
      }
      this.tableLoading = false
    })
  }

  protected searcherRef(): ITgFormBasicDialog {
    return this.ref('searcher') as ITgFormBasicDialog
  }

  protected initSearcher() {
    if (this.searcherInitable) {
      const searcherRef = this.searcherRef()
      if (isNotEmpty(searcherRef)) {
        searcherRef.initForm('view')
        this.searcherInitable = false
      }
    }
  }

  protected getSearcherModel() {
    const searcherRef = this.searcherRef()
    if (isNotEmpty(searcherRef)) {
      const model: any = searcherRef.getModel()
      Object.keys(model).forEach(key => {
        const value = model[key]
        if (isEmpty(value)) {
          delete model[key]
        }
      })
      if (!this.searcherLinkage) {
        /*
        如果未开启全局联动则进行手工同步 model
        理论上手工同步效率要高于联动
        */
        searcherRef.handleFormInput(model)
      }
      return model
    } else {
      return {}
    }
  }

  public showSearcher() {
    const searcherRef = this.searcherRef()
    if (isNotEmpty(searcherRef)) {
      this.initSearcher()
      searcherRef.showDialog()
    }
  }

  public hideSearcher() {
    const searcherRef = this.searcherRef()
    if (isNotEmpty(searcherRef)) {
      searcherRef.hideDialog()
    }
  }

  public doSearch() {
    this.page = 1
    this.loadData()
    this.hideSearcher()
  }

  public clearSearcher() {
    const searcherRef = this.searcherRef()
    if (isNotEmpty(searcherRef)) {
      searcherRef.clearForm()
    }
  }

  protected handleSearcherInput(model: any) {
    this.model = model
    this.$emit('input', model)
  }

  protected selectionChange(selection: any) {
    this.selectedRows = selection
  }

  public getSelectedRows() {
    return this.selectedRows
  }

  public defaultRef() {
    return 'table'
  }
}
